/*
 Copyright (C) 2009 are of boxtorrents
 boxtorrents, azureus, vuze, and java are copyrighted to their respective owner.

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; version 2 of the License.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 */
package com.boxtorrents.azureus;

import java.io.IOException;
import java.io.Serializable;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

import org.gudy.azureus2.plugins.PluginConfig;
import org.gudy.azureus2.plugins.PluginInterface;
import org.gudy.azureus2.plugins.config.ConfigParameter;
import org.gudy.azureus2.plugins.config.ConfigParameterListener;
import org.gudy.azureus2.plugins.download.Download;
import org.gudy.azureus2.plugins.download.DownloadManagerListener;
import org.gudy.azureus2.plugins.torrent.TorrentAttribute;
import org.gudy.azureus2.plugins.ui.config.BooleanParameter;
import org.gudy.azureus2.plugins.ui.config.IntParameter;
import org.gudy.azureus2.plugins.ui.config.Parameter;
import org.gudy.azureus2.plugins.ui.menus.MenuItem;
import org.gudy.azureus2.plugins.ui.menus.MenuItemFillListener;
import org.gudy.azureus2.plugins.ui.menus.MenuItemListener;
import org.gudy.azureus2.plugins.ui.model.BasicPluginConfigModel;
import org.gudy.azureus2.plugins.ui.tables.TableCell;
import org.gudy.azureus2.plugins.ui.tables.TableCellRefreshListener;
import org.gudy.azureus2.plugins.ui.tables.TableColumn;
import org.gudy.azureus2.plugins.ui.tables.TableContextMenuItem;
import org.gudy.azureus2.plugins.ui.tables.TableManager;
import org.gudy.azureus2.plugins.ui.tables.TableRow;

import com.boxtorrents.azureus.action.NotificationAction;
import com.boxtorrents.azureus.action.PauseDownloadAction;

/**
 * This class handles creation of configuration page
 * 
 * @author are of boxtorrents.com
 * @since 0.1.1
 */
public class ConfigPage implements Serializable {
	private static final long serialVersionUID = 3644267839205459008L;
	private static BasicPluginConfigModel confPage;
	private static LinkedList<MenuItem> menus = new LinkedList<MenuItem>();
	private static LinkedList<TableColumn> columns = new LinkedList<TableColumn>();
	private static PluginInterface pi = BoxTorrentsPlugin.getPluginInterface();
	private static Set<TableContextMenuItem> assignMenu = new HashSet<TableContextMenuItem>();

	/**
	 */
	public ConfigPage() {
		confPage = pi.getUIManager().createBasicPluginConfigModel(pi.getPluginID());
		confPage.addLabelParameter2("config.title");
		final IntParameter p1, p2, p3;
		final Parameter[] grp1 = {
		    confPage.addStringParameter2("param.userpage", "config.userpage",
		        "http://www.boxtorrents.com/user/someid/yournick.html"),
		    p1 = confPage.addIntParameter2("param.delay", "config.delay", 15),
		    p2 = confPage.addIntParameter2("param.ratio.warn",
		        "config.messagewarn", 150),
		    p3 = confPage.addIntParameter2("param.ratio.danger",
		        "config.messagedanger", 110),
		    confPage.addStringParameter2("param.browser", "config.browser",
		        "firefox") };
		confPage.createGroup("config.messagegrp1", grp1);
		p1.setMinimumRequiredUserMode(Parameter.MODE_INTERMEDIATE);
		p1.addConfigParameterListener(new ConfigParameterListener() {
			public void configParameterChanged(ConfigParameter par) {
				IntParameter p = (IntParameter)par;
				if (p.getValue() < 10) p.setValue(10);
			}
		});
		p2.addConfigParameterListener(new ConfigParameterListener() {
			public void configParameterChanged(ConfigParameter par) {
				IntParameter p = (IntParameter)par;
				if (p.getValue() < 0) p.setValue(0);
				if (p.getValue() < p3.getValue()) p.setValue(p3.getValue());
			}
		});
		p3.addConfigParameterListener(new ConfigParameterListener() {
			public void configParameterChanged(ConfigParameter par) {
				IntParameter p = (IntParameter)par;
				if (p.getValue() < 0) p.setValue(0);
				if (p.getValue() > p2.getValue()) p.setValue(p2.getValue());
			}
		});

		final BooleanParameter p7 = confPage.addBooleanParameter2(
		    "action.notify.enable", "config.notify.enable", true);
		final Parameter p8 = confPage.addBooleanParameter2("action.notify.always",
		    "config.notify.always", false);
		p7.addEnabledOnSelection(p8);
		p7.addConfigParameterListener(new ConfigParameterListener() {
			public void configParameterChanged(ConfigParameter par) {
				BooleanParameter p = (BooleanParameter)par;
				Set<StatCheckListener> listener = BoxTorrentsPlugin.getCheckListener();
				for (StatCheckListener lis : listener) {
					if (lis instanceof NotificationAction) {
						lis.onEnabled(p.getValue());
					}
				}
			}
		});
		final Parameter[] grp2 = { p7, p8 };
		confPage.createGroup("config.messagegrp2", grp2);

		final Parameter p10 = confPage
		    .addLabelParameter2("config.pausedownload.message");
		final BooleanParameter p5 = confPage.addBooleanParameter2(
		    "action.pausedownload.enable", "config.pausedownload.enable", true);
		final Parameter p9 = confPage.addBooleanParameter2(
		    "action.pausedownload.alert", "config.pausedownload.alert", true);
		p5.addEnabledOnSelection(p9);
		p5.addConfigParameterListener(new ConfigParameterListener() {
			public void configParameterChanged(ConfigParameter par) {
				BooleanParameter p = (BooleanParameter)par;
				Set<StatCheckListener> listener = BoxTorrentsPlugin.getCheckListener();
				for (StatCheckListener lis : listener) {
					if (lis instanceof PauseDownloadAction) {
						lis.onEnabled(p.getValue());
					}
				}
			}
		});
		final Parameter[] grp3 = { p10, p5, p9 };
		confPage.createGroup("config.messagegrp3", grp3);

		TableCellRefreshListener isBoxCellListener = new TableCellRefreshListener() {
			public void refresh(TableCell cell) {
				Object dataSource = cell.getDataSource();
				if (dataSource instanceof Download) {
					Download d = (Download)dataSource;
					if (Util.isBoxtorrentsDownload(d)) {
						cell.setText("Yes");
					} else {
						cell.setText("No");
					}
				}
			}
		};
		TableCellRefreshListener boxUploadCellListener = new TableCellRefreshListener() {
			public void refresh(TableCell cell) {
				Object dataSource = cell.getDataSource();
				if (dataSource instanceof Download) {
					Download d = (Download)dataSource;
					TorrentAttribute att = Util.getTorrentAttribute("box-up");
					if (d.hasAttribute(att) && d.getAttribute(att) != null) {
						cell.setText(d.getAttribute(att));
					} else {
						cell.setText("-");
					}
				}
			}
		};
		TableCellRefreshListener boxDownloadCellListener = new TableCellRefreshListener() {
			public void refresh(TableCell cell) {
				Object dataSource = cell.getDataSource();
				if (dataSource instanceof Download) {
					Download d = (Download)dataSource;
					TorrentAttribute att = Util.getTorrentAttribute("box-down");
					if (d.hasAttribute(att) && d.getAttribute(att) != null) {
						cell.setText(d.getAttribute(att));
					} else {
						cell.setText("-");
					}
				}
			}
		};
		TableCellRefreshListener boxSeederCellListener = new TableCellRefreshListener() {
			public void refresh(TableCell cell) {
				Object dataSource = cell.getDataSource();
				if (dataSource instanceof Download) {
					Download d = (Download)dataSource;
					TorrentAttribute att = Util.getTorrentAttribute("box-seeder");
					if (d.hasAttribute(att) && d.getAttribute(att) != null) {
						cell.setText(d.getAttribute(att));
					} else {
						cell.setText("-");
					}
				}
			}
		};
		TableCellRefreshListener boxLeecherCellListener = new TableCellRefreshListener() {
			public void refresh(TableCell cell) {
				Object dataSource = cell.getDataSource();
				if (dataSource instanceof Download) {
					Download d = (Download)dataSource;
					TorrentAttribute att = Util.getTorrentAttribute("box-leecher");
					if (d.hasAttribute(att) && d.getAttribute(att) != null) {
						cell.setText(d.getAttribute(att));
					} else {
						cell.setText("-");
					}
				}
			}
		};
		TableCellRefreshListener boxRatioCellListener = new TableCellRefreshListener() {
			public void refresh(TableCell cell) {
				Object dataSource = cell.getDataSource();
				if (dataSource instanceof Download) {
					Download d = (Download)dataSource;
					TorrentAttribute att = Util.getTorrentAttribute("box-ratio");
					if (d.hasAttribute(att) && d.getAttribute(att) != null) {
						cell.setText(d.getAttribute(att));
					} else {
						cell.setText("-");
					}
				}
			}
		};

		tableCreation("isBoxTorrents", isBoxCellListener);
		tableCreation("boxUpload", boxUploadCellListener);
		tableCreation("boxDownload", boxDownloadCellListener);
		tableCreation("boxSeeder", boxSeederCellListener);
		tableCreation("boxLeecher", boxLeecherCellListener);
		tableCreation("boxRatio", boxRatioCellListener);
		menuCreation();
		fixAttribute();
	}

	private void fixAttribute() {
		final TorrentAttribute att = Util.getTorrentAttribute("isBoxtorrent");

		pi.getDownloadManager().addListener(new DownloadManagerListener() {
			public void downloadAdded(Download d) {
				if (!d.hasAttribute(att)) {
					if (Util.isBoxtorrentsTracker(d)) d.setBooleanAttribute(att, true);
					else d.setBooleanAttribute(att, false);
				}
			}

			public void downloadRemoved(Download d) {}
		});

		Download[] downloads = pi.getDownloadManager().getDownloads();
		for (Download d : downloads) {
			if (!d.hasAttribute(att)) {
				if (Util.isBoxtorrentsTracker(d)) d.setBooleanAttribute(att, true);
				else d.setBooleanAttribute(att, false);
			}
		}
	}

	private void menuCreation() {
		TableManager tableManager = pi.getUIManager().getTableManager();
		MenuItemFillListener listBoxOnly = new MenuItemFillListener() {
			public void menuWillBeShown(MenuItem menu, Object obj) {
				boolean valid = false;
				if (obj != null && obj instanceof TableRow) {
					final Object data = ((TableRow)obj).getDataSource();
					if (data != null && data instanceof Download) {
						final Download d = (Download)data;
						if (Util.isBoxtorrentsDownload(d)) valid = true;
					}
				} else if (obj != null && obj instanceof TableRow[]) {
					TableRow[] rows = (TableRow[])obj;
					valid = true;
					for (TableRow row : rows) {
						final Object data = row.getDataSource();
						if (data instanceof Download) {
							final Download d = (Download)data;
							if (!Util.isBoxtorrentsDownload(d)) {
								valid = false;
								break;
							}
						} else {
							valid = false;
							break;
						}
					}
				}
				menu.setEnabled(valid);
			}
		};
		MenuItemFillListener listNonBoxOnly = new MenuItemFillListener() {
			public void menuWillBeShown(MenuItem menu, Object obj) {
				boolean valid = false;
				if (obj != null && obj instanceof TableRow) {
					final Object data = ((TableRow)obj).getDataSource();
					if (data != null && data instanceof Download) {
						final Download d = (Download)data;
						if (!Util.isBoxtorrentsDownload(d)) valid = true;
					}
				} else if (obj != null && obj instanceof TableRow[]) {
					TableRow[] rows = (TableRow[])obj;
					valid = true;
					for (TableRow row : rows) {
						final Object data = row.getDataSource();
						if (data instanceof Download) {
							final Download d = (Download)data;
							if (Util.isBoxtorrentsDownload(d)) {
								valid = false;
								break;
							}
						} else {
							valid = false;
							break;
						}
					}
				}
				menu.setEnabled(valid);
			}
		};

		TableContextMenuItem parent = tableManager.addContextMenuItem(
		    TableManager.TABLE_MYTORRENTS_INCOMPLETE, "menu.boxmenu");
		addBoxMenuItem(tableManager, parent, listBoxOnly, listNonBoxOnly);

		parent = tableManager.addContextMenuItem(
		    TableManager.TABLE_MYTORRENTS_COMPLETE, "menu.boxmenu");
		addBoxMenuItem(tableManager, parent, listBoxOnly, listNonBoxOnly);

		parent = tableManager.addContextMenuItem(
		    TableManager.TABLE_MYTORRENTS_INCOMPLETE_BIG, "menu.boxmenu");
		addBoxMenuItem(tableManager, parent, listBoxOnly, listNonBoxOnly);

		parent = tableManager.addContextMenuItem(
		    TableManager.TABLE_MYTORRENTS_COMPLETE_BIG, "menu.boxmenu");
		addBoxMenuItem(tableManager, parent, listBoxOnly, listNonBoxOnly);

		parent = tableManager.addContextMenuItem(
		    TableManager.TABLE_MYTORRENTS_ALL_BIG, "menu.boxmenu");
		addBoxMenuItem(tableManager, parent, listBoxOnly, listNonBoxOnly);
	}

	private void addBoxMenuItem(TableManager tableManager,
	    TableContextMenuItem parent, MenuItemFillListener lisBoxOnly,
	    MenuItemFillListener lisNonBoxOnly) {

		parent.setStyle(MenuItem.STYLE_MENU);
		parent.setEnabled(false);
		parent.addFillListener(new MenuItemFillListener() {
			public void menuWillBeShown(MenuItem menu, Object obj) {
				if (obj == null) menu.setEnabled(false);
				else menu.setEnabled(true);
			}
		});
		menus.add(parent);

		TableContextMenuItem item = tableManager.addContextMenuItem(parent,
		    "menu.boxmenu.stat");
		item.addListener(new MenuItemListener() {
			public void selected(MenuItem arg0, Object arg1) {
				PluginConfig pconf = pi.getPluginconfig();
				try {
					Runtime.getRuntime().exec(
					    pconf.getPluginStringParameter("param.browser", "firefox")
					        + " "
					        + pconf.getPluginStringParameter("param.userpage",
					            "http://www.boxtorrents.com"));
				} catch (IOException e) {
				}
			}
		});
		menus.add(item);

		item = tableManager.addContextMenuItem(parent, "menu.boxmenu.torrentpage");
		item.setEnabled(false);
		item.addFillListener(new MenuItemFillListener() {
			public void menuWillBeShown(MenuItem menu, Object obj) {
				if (obj instanceof TableRow[]) {
					TableRow[] rows = (TableRow[])obj;
					boolean valid = false;
					if (rows.length == 1) {
						Download d = (Download)rows[0].getDataSource();
						TorrentAttribute att = Util.getTorrentAttribute("box-url");
						if (d.hasAttribute(att) && d.getAttribute(att) != null)
						  valid = true;
					}
					menu.setEnabled(valid);
				}
				// backward compatibility
				if (obj instanceof TableRow) {
					TableRow r = (TableRow)obj;
					menuWillBeShown(menu, new TableRow[] { r });
				}
			}
		});
		item.addListener(new MenuItemListener() {
			public void selected(MenuItem menu, Object obj) {
				TorrentAttribute url = Util.getTorrentAttribute("box-url");
				Runtime run = Runtime.getRuntime();
				PluginConfig pconf = pi.getPluginconfig();
				if (obj instanceof TableRow) {
					Download d = (Download)((TableRow)obj).getDataSource();
					if (d.hasAttribute(url) && d.getAttribute(url) != null) {
						try {
							run.exec(pconf.getPluginStringParameter("param.browser",
							    "firefox")
							    + " " + d.getAttribute(url));
						} catch (IOException e) {
						}
					}
				} else if (obj instanceof TableRow[]) {
					TableRow[] rows = (TableRow[])obj;
					for (TableRow row : rows) {
						Download d = (Download)row.getDataSource();
						if (d.hasAttribute(url) && d.getAttribute(url) != null) {
							try {
								run.exec(pconf.getPluginStringParameter("param.browser",
								    "firefox")
								    + " " + d.getAttribute(url));
							} catch (IOException e) {
							}
						}
					}
				}
			}
		});
		menus.add(item);

		item = tableManager.addContextMenuItem(parent, "menu.boxmenu.force");
		item.addFillListener(lisBoxOnly);
		item.addListener(new MenuItemListener() {
			public void selected(MenuItem arg0, Object arg1) {
				BoxTorrentsPlugin.forceCheck();
			}
		});
		menus.add(item);

		item = tableManager.addContextMenuItem(parent, "separator");
		item.setStyle(MenuItem.STYLE_SEPARATOR);
		menus.add(item);

		item = tableManager.addContextMenuItem(parent, "menu.boxmenu.assign");
		item.setEnabled(false);
		item.addFillListener(new MenuItemFillListener() {
			public void menuWillBeShown(MenuItem item, Object obj) {
				if (obj instanceof TableRow || obj instanceof TableRow[]) {
					recreateAssignMenu();
				}
			}
		});
		item.setStyle(MenuItem.STYLE_MENU);
		assignMenu.add(item);
		menus.add(item);

		item = tableManager.addContextMenuItem(parent, "menu.boxmenu.unassign");
		item.setEnabled(false);
		item.addFillListener(new MenuItemFillListener() {

			public void menuWillBeShown(MenuItem menu, Object obj) {
				TorrentAttribute att = Util.getTorrentAttribute("box-url");
				if (obj instanceof TableRow[]) {
					TableRow[] rows = (TableRow[])obj;
					for (TableRow row : rows) {
						Download d = (Download)row.getDataSource();
						if (d.hasAttribute(att) && d.getAttribute(att) != null) {
							menu.setEnabled(true);
						} else {
							menu.setEnabled(false);
						}
					}
				}
				if (obj instanceof TableRow) {
					menuWillBeShown(menu, new TableRow[] { (TableRow)obj });
				}
			}
		});
		item.addListener(new MenuItemListener() {
			public void selected(MenuItem menu, Object obj) {
				if (obj instanceof TableRow) {
					selected(menu, new TableRow[] { (TableRow)obj });
				} else if (obj instanceof TableRow[]) {
					TableRow[] rows = (TableRow[])obj;
					for (TableRow row : rows) {
						Download d = (Download)row.getDataSource();
						unset(d);
					}
				}
			}

			private void unset(Download d) {
				d.setAttribute(Util.getTorrentAttribute("box-name"), null);
				d.setAttribute(Util.getTorrentAttribute("box-url"), null);
				d.setAttribute(Util.getTorrentAttribute("box-up"), null);
				d.setAttribute(Util.getTorrentAttribute("box-down"), null);
				d.setAttribute(Util.getTorrentAttribute("box-ratio"), null);
				d.setAttribute(Util.getTorrentAttribute("box-seeder"), null);
				d.setAttribute(Util.getTorrentAttribute("box-leecher"), null);
			}
		});
		menus.add(item);

		item = tableManager.addContextMenuItem(parent, "separator");
		item.setStyle(MenuItem.STYLE_SEPARATOR);
		menus.add(item);

		item = tableManager.addContextMenuItem(parent, "menu.boxmenu.markbox");
		item.setEnabled(false);
		item.addFillListener(lisNonBoxOnly);
		item.addListener(new MenuItemListener() {
			public void selected(MenuItem menu, Object obj) {
				final TorrentAttribute att = Util.getTorrentAttribute("isBoxtorrent");
				if (obj == null) return;
				if (obj instanceof TableRow) {
					if (((TableRow)obj).getDataSource() instanceof Download) {
						Download d = (Download)((TableRow)obj).getDataSource();
						d.setBooleanAttribute(att, true);
					}
				} else if (obj instanceof TableRow[]) {
					TableRow[] rows = (TableRow[])obj;
					for (TableRow row : rows) {
						if (row.getDataSource() instanceof Download) {
							Download d = (Download)row.getDataSource();
							d.setBooleanAttribute(att, true);
						}
					}
				}
			}
		});
		menus.add(item);

		item = tableManager.addContextMenuItem(parent, "menu.boxmenu.unmarkbox");
		item.setEnabled(false);
		item.addFillListener(lisBoxOnly);
		item.addListener(new MenuItemListener() {
			public void selected(MenuItem menu, Object obj) {
				final TorrentAttribute att = Util.getTorrentAttribute("isBoxtorrent");
				if (obj == null) return;
				if (obj instanceof TableRow) {
					if (((TableRow)obj).getDataSource() instanceof Download) {
						Download d = (Download)((TableRow)obj).getDataSource();
						d.setBooleanAttribute(att, false);
					}
				} else if (obj instanceof TableRow[]) {
					TableRow[] rows = (TableRow[])obj;
					for (TableRow row : rows) {
						if (row.getDataSource() instanceof Download) {
							Download d = (Download)row.getDataSource();
							d.setBooleanAttribute(att, false);
						}
					}
				}
			}
		});
		menus.add(item);

	}

	private void configureColumn(TableManager tableManager, TableColumn column,
	    TableCellRefreshListener listener) {
		column.setType(TableColumn.TYPE_TEXT_ONLY);
		column.setRefreshInterval(TableColumn.INTERVAL_GRAPHIC);
		column.addCellRefreshListener(listener);
		column.setAlignment(TableColumn.ALIGN_CENTER);
		tableManager.addColumn(column);
		columns.add(column);
	}

	private void tableCreation(String name, TableCellRefreshListener listener) {
		TableManager tableManager = pi.getUIManager().getTableManager();
		TableColumn column = tableManager.createColumn(
		    TableManager.TABLE_MYTORRENTS_INCOMPLETE, name);
		configureColumn(tableManager, column, listener);
		column = tableManager.createColumn(
		    TableManager.TABLE_MYTORRENTS_INCOMPLETE_BIG, name);
		configureColumn(tableManager, column, listener);
		column = tableManager.createColumn(TableManager.TABLE_MYTORRENTS_COMPLETE,
		    name);
		configureColumn(tableManager, column, listener);
		column = tableManager.createColumn(
		    TableManager.TABLE_MYTORRENTS_COMPLETE_BIG, name);
		configureColumn(tableManager, column, listener);
		column = tableManager.createColumn(TableManager.TABLE_MYTORRENTS_ALL_BIG,
		    name);
		configureColumn(tableManager, column, listener);
	}

	/**
	 * @return main menu
	 */
	public Set<MenuItem> getMainMenu() {
		HashSet<MenuItem> result = new HashSet<MenuItem>();
		for (MenuItem item : menus) {
			if (item.getResourceKey().equals("menu.boxmenu")) result.add(item);
		}
		return result;
	}

	/**
	 */
	public void recreateAssignMenu() {
		Set<TorrentData> torrents = BoxTorrentsPlugin.getGatherer().getLastData()
		    .getTorrentData();
		TableManager manager = pi.getUIManager().getTableManager();
		final TorrentAttribute attName = Util.getTorrentAttribute("box-name");
		final TorrentAttribute attUrl = Util.getTorrentAttribute("box-url");
		final TorrentAttribute attUp = Util.getTorrentAttribute("box-up");
		final TorrentAttribute attDown = Util.getTorrentAttribute("box-down");
		final TorrentAttribute attRatio = Util.getTorrentAttribute("box-ratio");
		final TorrentAttribute attSeeder = Util.getTorrentAttribute("box-seeder");
		final TorrentAttribute attLeecher = Util.getTorrentAttribute("box-leecher");

		Set<TorrentData> assigned = new HashSet<TorrentData>();

		// updating attributes
		Download[] downloads = pi.getDownloadManager().getDownloads();
		for (Download d : downloads) {
			if (d.hasAttribute(attUrl) && d.getAttribute(attUrl) != null) {
				String tmp = d.getAttribute(attUrl);
				for (TorrentData data : torrents) {
					if (data.getUrl().toExternalForm().equals(tmp)) {
						d.setAttribute(attName, data.getName());
						d.setAttribute(attUp, data.getUploaded());
						d.setAttribute(attDown, data.getDownloaded());
						d.setAttribute(attRatio, data.getRatio());
						d.setAttribute(attSeeder, String.valueOf(data.getNumSeeder()));
						d.setAttribute(attLeecher, String.valueOf(data.getNumLeecher()));
						assigned.add(data);
					}
				}
			}
		}

		for (TableContextMenuItem parent : assignMenu) {
			parent.removeAllChildItems();
			for (final TorrentData data : torrents) {
				if (assigned.contains(data)) continue;
				TableContextMenuItem item = manager.addContextMenuItem(parent,
				    "menu.assign.torrent");
				item.setText(data.getName());
				item.addListener(new MenuItemListener() {
					public void selected(MenuItem menu, Object obj) {
						if (obj == null) return;
						if (obj instanceof TableRow) {
							selected(menu, new TableRow[] { (TableRow)obj });
						} else if (obj instanceof TableRow[]) {
							TableRow[] rows = (TableRow[])obj;
							if (rows.length != 1) return;
							if (rows[0].getDataSource() instanceof Download) {
								Download d = (Download)rows[0].getDataSource();
								setData(d, data);
							}
						}
					}

					private void setData(Download d, TorrentData data) {
						d.setAttribute(attName, data.getName());
						d.setAttribute(attUrl, data.getUrl().toExternalForm());
						d.setAttribute(attUp, data.getUploaded());
						d.setAttribute(attDown, data.getDownloaded());
						d.setAttribute(attRatio, data.getRatio());
						d.setAttribute(attSeeder, String.valueOf(data.getNumSeeder()));
						d.setAttribute(attLeecher, String.valueOf(data.getNumLeecher()));
					}
				});
			}
			if (parent.getItems() == null || parent.getItems().length == 0) parent
			    .setEnabled(false);
			else parent.setEnabled(true);
		}
	}
}
